package main

import (
	"bufio"
	"errors"
	"fmt"
	"io"
	"os"
	"sync"
)

//并发实现写文件

var (
	rwChanel   = make(chan string, 10240)
	readFinsh  = make(chan struct{})
	writeFinsh = make(chan struct{})
	wg         sync.WaitGroup
)

func Concurrent_readFile(fileName string) {
	fin, err := os.Open(fileName)
	if err != nil {
		fmt.Println(err)
		return
	} else {
		defer fin.Close()
		reader := bufio.NewReader(fin)
		for {
			if line, err := reader.ReadString('\n'); err != nil {
				if err == io.EOF {
					if len(line) > 0 {
						rwChanel <- line
						rwChanel <- "\n"
					}
					break
				}
			} else {
				rwChanel <- line
			}
		}
	}
}

func Concurrent_writeFile(fileName string) {
	fout, err := os.OpenFile(fileName, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
	if err != nil {
		fmt.Println(err)
		return
	} else {
		defer fout.Close()
		writer := bufio.NewWriter(fout)
	LOOP:
		for {
			select {
			case line := <-rwChanel:
				writer.WriteString(line)
			case <-readFinsh:
				close(rwChanel)
				if len(rwChanel) > 0 {
					for str := range rwChanel {
						writer.WriteString(string(str))
					}
				}
				break LOOP
			}
		}
		writer.Flush()
	}
}

func readFilePath(path string) ([]string, error) {
	rect := make([]string, 0, 16)
	entry, err := os.ReadDir(path)
	if err != nil {
		fmt.Println(err)
		return nil, errors.New("找不到对应路径")
	} else {
		for _, ele := range entry {
			if ele.IsDir() {
				readFilePath(path + "/" + ele.Name())
			} else {
				rect = append(rect, (path + "/" + ele.Name()))
			}
		}
	}

	return rect, nil
}

func Concurrent_mergeFile(filePath string, mergeFileName string) {
	files, err := readFilePath(filePath)
	if err != nil {
		fmt.Println(err)
		return
	} else {
		n := len(files)
		readFinsh = make(chan struct{}, n)
		wg.Add(n)
		go func(w_file string) {
			Concurrent_writeFile(w_file)
			writeFinsh <- struct{}{}
		}(mergeFileName)

		for _, ele := range files {
			go func(r_file string) {
				Concurrent_readFile(r_file)
				wg.Done()
			}(ele)
		}

		wg.Wait()
		readFinsh <- struct{}{}

		<-writeFinsh
	}
}

func main() {
	Concurrent_mergeFile("dir", "merge.txt")
}
